package cn.iocoder.yudao.module.shop.service.dayuser;

import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletRechargeDO;
import cn.iocoder.yudao.module.shop.dal.dataobject.daystatistics.ShopDayStatisticsDO;
import cn.iocoder.yudao.module.shop.dal.dataobject.item.ShopItemDO;
import cn.iocoder.yudao.module.shop.dal.dataobject.order.ShopOrderDO;
import cn.iocoder.yudao.module.shop.dal.dataobject.order.ShopOrderItemDO;
import cn.iocoder.yudao.module.shop.enums.store.ChargeTypeEnum;
import cn.iocoder.yudao.module.shop.service.handlestrategy.ShopHandleStrategyService;
import cn.iocoder.yudao.module.shop.service.item.ShopItemService;
import cn.iocoder.yudao.module.shop.service.order.ShopOrderItemService;
import cn.iocoder.yudao.module.shop.service.order.dto.ShopOrderItemHandleDTO;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import cn.iocoder.yudao.module.system.dal.dataobject.permission.UserRoleDO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import javax.print.DocFlavor;

import org.springframework.validation.annotation.Validated;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import cn.iocoder.yudao.module.shop.controller.admin.dayuser.vo.*;
import cn.iocoder.yudao.module.shop.dal.dataobject.dayuser.ShopDayUserDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;

import cn.iocoder.yudao.module.shop.convert.dayuser.ShopDayUserConvert;
import cn.iocoder.yudao.module.shop.dal.mysql.dayuser.ShopDayUserMapper;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.shop.enums.ErrorCodeConstants.*;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;

/**
 * 艾灸师每日统计 Service 实现类
 *
 * @author 曹建伟
 */
@Service
@Validated
public class ShopDayUserServiceImpl implements ShopDayUserService {

    @Resource
    private ShopDayUserMapper dayUserMapper;

    @Resource
    private ShopHandleStrategyService shopHandleStrategyService;

    @Resource
    private ShopOrderItemService shopOrderItemService;

    @Resource
    private ShopItemService shopItemService;

    @Override
    public Long createDayUser(ShopDayUserCreateReqVO createReqVO) {
        // 插入
        ShopDayUserDO dayUser = ShopDayUserConvert.INSTANCE.convert(createReqVO);
        dayUserMapper.insert(dayUser);
        // 返回
        return dayUser.getId();
    }

    @Override
    public void updateDayUser(ShopDayUserUpdateReqVO updateReqVO) {
        // 校验存在
        validateDayUserExists(updateReqVO.getId());
        // 更新
        ShopDayUserDO updateObj = ShopDayUserConvert.INSTANCE.convert(updateReqVO);
        dayUserMapper.updateById(updateObj);
    }

    @Override
    public void deleteDayUser(Long id) {
        // 校验存在
        validateDayUserExists(id);
        // 删除
        dayUserMapper.deleteById(id);
    }

    private void validateDayUserExists(Long id) {
        if (dayUserMapper.selectById(id) == null) {
            throw exception(DAY_USER_NOT_EXISTS);
        }
    }

    @Override
    public ShopDayUserDO getDayUser(Long id) {

        return dayUserMapper.selectById(id);
    }

    @Override
    public List<ShopDayUserDO> getDayUserList(Collection<Long> ids) {
        if (CollUtil.isEmpty(ids)) {
            return ListUtil.empty();
        }
        return dayUserMapper.selectBatchIds(ids);
    }

    @Override
    public List<ShopDayUserDO> getDayUserListByUserId(LocalDateTime time, Long userId){
        String dateRight = time.format(DateTimeFormatter.ofPattern("yyyyMM"));
        return dayUserMapper.selectListByUserId(dateRight, userId);
    }

    @Override
    public Boolean confirm(Long id){
        // 校验存在
        validateDayUserExists(id);
        // 删除
        ShopDayUserDO shopDayUserDO = dayUserMapper.selectById(id);
        if(shopDayUserDO == null){
            throw exception(DAY_USER_NOT_EXISTS);
        }

        if(shopDayUserDO.getConfirmed()){
            return true;
        }

        shopDayUserDO.setConfirmed(true);
        dayUserMapper.updateById(shopDayUserDO);

        return true;
    }

    @Override
    public PageResult<ShopDayUserDO> getDayUserPage(ShopDayUserPageReqVO pageReqVO) {
        return dayUserMapper.selectPage(pageReqVO);
    }

    @Override
    public List<ShopDayUserDO> getDayUserList(ShopDayUserExportReqVO exportReqVO) {
        return dayUserMapper.selectList(exportReqVO);
    }

    private ShopDayUserDO get(String dateId, Long memberId){
        ShopDayUserDO userDO = dayUserMapper.selectOne(new LambdaQueryWrapper<ShopDayUserDO>()
                .eq(ShopDayUserDO::getDateId, dateId)
                .eq(ShopDayUserDO::getUserId, memberId));

        return userDO;
    }

    private ShopDayUserDO getOrCreate(String dateId, Long memberId, Long tenantId){
        ShopDayUserDO userDO = dayUserMapper.selectOne(new LambdaQueryWrapper<ShopDayUserDO>()
                .eq(ShopDayUserDO::getDateId, dateId)
                .eq(ShopDayUserDO::getUserId, memberId));

        if(userDO == null){
            userDO = new ShopDayUserDO();

            LocalDateTime now = LocalDateTime.now();
            userDO.setUpdateTime(now);
            userDO.setCreateTime(now);

            userDO.setUserId(memberId);
            userDO.setDateId(dateId);
            userDO.setTenantId(tenantId);

            userDO.setCount(0);
            userDO.setHandlePrice(0);
            userDO.setExtHandlePrice(0);

            userDO.setTotalMemberTimes(0);
            userDO.setVipTimes(0);
            userDO.setNovipTimes(0);
            userDO.setNewMemberCount(0);

            userDO.setChargeTotalCount(0);
            userDO.setChargeTotalPrice(0);
            userDO.setChargeContinueCount(0);;
            userDO.setChargeFirstCount(0);
            userDO.setChargeNoContinueCount(0);
            userDO.setChargeAfterTimesCount(0);

            userDO.setFirstChargeBonus(0);
            userDO.setIsHoliday(false);
            userDO.setConfirmed(false);

            dayUserMapper.insert(userDO);

            userDO = dayUserMapper.selectOne(new LambdaQueryWrapper<ShopDayUserDO>()
                    .eq(ShopDayUserDO::getDateId, dateId)
                    .eq(ShopDayUserDO::getUserId, memberId));

            return userDO;
        }

        return userDO;
    }

    @Override
    public Boolean recordOrder(ShopOrderDO order, Boolean isNewMember, Long rechargeOrderCount){
        String dateId = order.getStartTime().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
        ShopDayUserDO userDO = getOrCreate(dateId, order.getUserId(), order.getTenantId());

        if(userDO == null){
            throw exception(DAY_USER_CREATE_ERROR);
        }

        userDO.setCreateTime(order.getStartTime());
        userDO.setUpdateTime(order.getStartTime());

        ShopOrderItemHandleDTO handleDTO = shopOrderItemService.getHandleByOrderId(order.getId());

        userDO.setCount(userDO.getCount()+ handleDTO.getHandleCount());
        userDO.setHandlePrice(shopHandleStrategyService.calcHandlePrice(userDO.getUserId(), userDO.getCount(), order.getTenantId()));
        userDO.setExtHandlePrice(userDO.getExtHandlePrice() + handleDTO.getExtHandlePrice());
        if(handleDTO.getHandleRate() > 0){
            double rate = (double)handleDTO.getHandleRate() / 100;
            int value = (int)(rate * order.getPayPrice());
            userDO.setExtHandlePrice(userDO.getExtHandlePrice() + value);
        }

        userDO.setTotalMemberTimes(userDO.getTotalMemberTimes() + 1);
        if(order.getWalletCharge()){
            userDO.setVipTimes(userDO.getVipTimes() + 1);
        }else{
            userDO.setNovipTimes(userDO.getNovipTimes() + 1);
            if(!order.getTimesCharge()){
                if(rechargeOrderCount > 0){
                    userDO.setChargeNoContinueCount(userDO.getChargeNoContinueCount() + 1);
                }
            }
        }

        if(isNewMember){
            userDO.setNewMemberCount(userDO.getNewMemberCount() + 1);
        }

        dayUserMapper.updateById(userDO);

        return true;
    }

    @Override
    public Boolean recordHoliday(LocalDateTime time,AdminUserRespDTO user){
        String dateId = time.format(DateTimeFormatter.ofPattern("yyyyMMdd"));
        ShopDayUserDO userDO = getOrCreate(dateId, user.getId(), user.getTenantId());

        userDO.setIsHoliday(true);

        dayUserMapper.updateById(userDO);
        return true;
    }

    @Override
    public Boolean rollbackOrder(ShopOrderDO order){
        String dateId = order.getStartTime().format(DateTimeFormatter.ofPattern("yyyyMMdd"));

        ShopDayUserDO userDO = getOrCreate(dateId, order.getUserId(), order.getTenantId());

        if(userDO == null){
            return true;
        }

        ShopOrderItemHandleDTO handleDTO = shopOrderItemService.getHandleByOrderId(order.getId());

        userDO.setCount(userDO.getCount() - handleDTO.getHandleCount());
        userDO.setHandlePrice(shopHandleStrategyService.calcHandlePrice(userDO.getUserId(), userDO.getCount(), order.getTenantId()));
        userDO.setExtHandlePrice(userDO.getExtHandlePrice() - handleDTO.getExtHandlePrice());
        if(handleDTO.getHandleRate() > 0){
            double rate = (double)handleDTO.getHandleRate() / 100;
            int value = (int)(rate * order.getPayPrice());
            userDO.setExtHandlePrice(userDO.getExtHandlePrice() - value);
        }

        userDO.setTotalMemberTimes(userDO.getTotalMemberTimes() - 1);
        if(order.getWalletCharge()){
            userDO.setVipTimes(userDO.getVipTimes() - 1);
        }else{
            userDO.setNovipTimes(userDO.getNovipTimes() - 1);
        }

        dayUserMapper.updateById(userDO);

        return true;
    }

    @Override
    public Boolean recordPayOrder(PayWalletRechargeDO payOrder, Long masterId, ChargeTypeEnum chargeType){
        String dateId = payOrder.getCreateTime().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
        ShopDayUserDO userDO = getOrCreate(dateId, masterId, payOrder.getTenantId());

        if(userDO == null){
            throw exception(DAY_USER_CREATE_ERROR);
        }

        userDO.setChargeTotalCount(userDO.getChargeTotalCount() + 1);
        userDO.setChargeTotalPrice(userDO.getChargeTotalPrice() + payOrder.getPayPrice());
        if(chargeType.getType().equals(ChargeTypeEnum.CONTINUE.getType())){
            userDO.setChargeContinueCount(userDO.getChargeContinueCount()+1);
        }else if(chargeType.getType().equals(ChargeTypeEnum.FIRST.getType())){
            userDO.setChargeFirstCount(userDO.getChargeFirstCount() + 1);
        }else if(chargeType.getType().equals(ChargeTypeEnum.CONVERT.getType())){
            userDO.setChargeAfterTimesCount(userDO.getChargeAfterTimesCount() + 1);
        }

        if(chargeType.getType().equals(ChargeTypeEnum.FIRST.getType())){
            userDO.setFirstChargeBonus(userDO.getFirstChargeBonus() + shopHandleStrategyService.calcFirstChargeBonus(payOrder.getPayPrice(), userDO.getTenantId()));
        }

        dayUserMapper.updateById(userDO);

        return true;
    }

    public Boolean recordTimesChargePay(Integer payPrice, Long memberId, Long masterId, ChargeTypeEnum chargeType, Long tenantId){
        String dateId = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
        ShopDayUserDO userDO = getOrCreate(dateId, masterId, tenantId);

        if(userDO == null){
            throw exception(DAY_USER_CREATE_ERROR);
        }

        userDO.setChargeTotalCount(userDO.getChargeTotalCount() + 1);
        userDO.setChargeTotalPrice(userDO.getChargeTotalPrice() + payPrice);
        if(chargeType.getType().equals(ChargeTypeEnum.CONTINUE.getType())){
            userDO.setChargeContinueCount(userDO.getChargeContinueCount()+1);
        }else if(chargeType.getType().equals(ChargeTypeEnum.FIRST.getType())){
            userDO.setChargeFirstCount(userDO.getChargeFirstCount() + 1);
        }else if(chargeType.getType().equals(ChargeTypeEnum.CONVERT.getType())){
            userDO.setChargeAfterTimesCount(userDO.getChargeAfterTimesCount() + 1);
        }

        if(chargeType.getType().equals(ChargeTypeEnum.FIRST.getType())){
            userDO.setFirstChargeBonus(userDO.getFirstChargeBonus() + shopHandleStrategyService.calcFirstChargeBonus(payPrice, userDO.getTenantId()));
        }

        dayUserMapper.updateById(userDO);

        return true;
    }

    @Override
    public List<ShopDayUserDO> getDayUserListByTime(LocalDateTime startTime, LocalDateTime endTime, Long tenantId){
        return dayUserMapper.selectList(startTime, endTime, tenantId);
    }

    @Override
    public void dayJob(List<AdminUserRespDTO> userList){
        String dateId = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));

        for(int i = 0; i<userList.size(); i++){
            AdminUserRespDTO user = userList.get(i);
            getOrCreate(dateId, user.getId(), user.getTenantId());
        }
    }

}
